﻿using System;
using System.Collections.Generic;
using System.Text;
using XchangeStreamer.Types;
using System.Xml.Linq;
using System.Web;
using XchangeStreamer.Publisher.SDK;
using System.Threading.Tasks;
using System.Threading;
using XchangeStreamer.Types.Google;
using System.Net;

namespace GooglePublisher
{
    class Program
    {
        private static string interdayUrl = "http://www.google.com/ig/api?";
        private static string historyUrl = "http://www.google.com/finance/historical?q={0}&startdate={1}&enddate={2}&histperiod={3}&output=csv";

        private static Connector connector;
        private static long stop = 0;

        static void Main(string[] args)
        {
            Console.Write("Please enter streamer info (IP/Port):");
            string[] streamerInfo = Console.ReadLine().Split('/');

            Console.Write("Please enter cache server info (IP/Port):");
            string[] cacheServerInfo = Console.ReadLine().Split('/');

            string streamerIP = streamerInfo.Length < 2 ? "localhost" : streamerInfo[0];
            string streamerPort = streamerInfo.Length < 2 ? null : streamerInfo[1];
            string cacheServerIP = cacheServerInfo.Length < 2 ? "localhost" : cacheServerInfo[0];
            string cacheServerPort = cacheServerInfo.Length < 2 ? null : cacheServerInfo[1];

            connector = Connector.Connection;
            connector.Connect(streamerIP, streamerPort, cacheServerIP, cacheServerPort);

            connector.CreateTopic("Orders");

            var start = DateTime.UtcNow.TimeOfDay;
            Console.WriteLine("Start Time: {0}", start);

            Task.Factory.StartNew(PublishRealTime);

            Console.ReadKey();

            string symbol = "msft";
            DateTime s = new DateTime(2000, 1, 1);
            DateTime e = new DateTime(2011, 4, 16);
            Period period = Period.Daily;
            Task.Factory.StartNew(() =>
            {
                PublishHistory(symbol, s, e, period);
            });
            Console.ReadKey();

            //Interlocked.Increment(ref stop);
            //connector.Disconnect();

            //var end = DateTime.UtcNow.TimeOfDay;
            //Console.WriteLine("End Time: {0}", end);

            //Console.WriteLine("Test Time: {0}", end.Subtract(start));
            //Console.ReadKey();
        }

        private static void PublishRealTime()
        {
            var c = true;
            while (c)
            {
                //c = false;
                var size = connector.Publish<RealTime, List<RealTime>>(1, FetchRealTime("goog", "msft"));
                Console.WriteLine("Size: {0}", size);
                //System.Threading.Thread.Sleep(500);
                if (Interlocked.Read(ref stop) == 1)
                {
                    c = false;
                }
            }
        }

        private static List<RealTime> FetchRealTime(params string[] symbols)
        {
            if (symbols.Length < 1)
            {
                return null;
            }

            string info = interdayUrl;
            for (int i = 0; i < symbols.Length; i++)
            {
                info += "stock=" + HttpUtility.UrlEncode(symbols[i]) + "&";
            }
            info = info.Remove(info.Length - 1);

            XDocument doc = XDocument.Load(info);
            var records = doc.Root.Elements("finance");

            List<RealTime> tickers = new List<RealTime>(symbols.Length);

            foreach (var record in records)
            {
                var ticker = new RealTime();

                ticker.Symbol = record.Element("symbol").Attribute("data").Value;
                ticker.PrettySymbol = record.Element("pretty_symbol").Attribute("data").Value;
                ticker.SymbolLookupUrl = record.Element("symbol_lookup_url").Attribute("data").Value;
                ticker.Company = record.Element("company").Attribute("data").Value;
                ticker.Exchange = record.Element("exchange").Attribute("data").Value;
                ticker.ExchangeTimeZone = record.Element("exchange_timezone").Attribute("data").Value;
                ticker.ExchangeUtcOffest = record.Element("exchange_utc_offset").Attribute("data").Value;

                var temp = record.Element("exchange_closing").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.ExchangeClosing = int.Parse(temp);
                }

                temp = record.Element("divisor").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Divisor = int.Parse(temp);
                }

                ticker.Currency = record.Element("currency").Attribute("data").Value;

                temp = record.Element("last").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Last = decimal.Parse(temp);
                }

                temp = record.Element("high").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.High = decimal.Parse(temp);
                }

                temp = record.Element("low").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Low = decimal.Parse(temp);
                }

                temp = record.Element("volume").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Volume = uint.Parse(temp);
                }

                temp = record.Element("avg_volume").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.AvgVolume = uint.Parse(temp);
                }

                temp = record.Element("market_cap").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.MarketCap = decimal.Parse(temp);
                }

                temp = record.Element("open").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Open = decimal.Parse(temp);
                }

                temp = record.Element("y_close").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.YClose = decimal.Parse(temp);
                }

                temp = record.Element("change").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Change = decimal.Parse(temp);
                }

                temp = record.Element("perc_change").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.PercentChange = decimal.Parse(temp);
                }

                temp = record.Element("delay").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.Delay = int.Parse(temp);
                }

                ticker.TradeTimeStamp = record.Element("trade_timestamp").Attribute("data").Value;

                temp = record.Element("trade_date_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.TradeDateUtc = DateTime.ParseExact(temp, "yyyyMMdd", null);
                }

                temp = record.Element("trade_time_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.TradeTimeUtc = TimeSpan.ParseExact(temp, "hhmmss", null);
                }

                temp = record.Element("current_date_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.CurrentDateUtc = DateTime.ParseExact(temp, "yyyyMMdd", null);
                }

                temp = record.Element("current_time_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.CurrentTimeUtc = TimeSpan.ParseExact(temp, "hhmmss", null);
                }

                ticker.SymbolUrl = record.Element("symbol_url").Attribute("data").Value;
                ticker.ChartUrl = record.Element("chart_url").Attribute("data").Value;
                ticker.EcnUrl = record.Element("ecn_url").Attribute("data").Value;
                ticker.IsldLast = record.Element("isld_last").Attribute("data").Value;

                temp = record.Element("isld_trade_date_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.IsldTradeDateUtc = DateTime.ParseExact(temp, "yyyyMMdd", null);
                }

                temp = record.Element("isld_trade_time_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.IsldTradeTimeUtc = TimeSpan.ParseExact(temp, "hhmmss", null);
                }

                temp = record.Element("brut_last").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.BrutLast = decimal.Parse(temp);
                }

                temp = record.Element("brut_trade_date_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.BrutTradeDateUtc = DateTime.ParseExact(temp, "yyyyMMdd", null);
                }

                temp = record.Element("brut_trade_time_utc").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.BrutTradeTimeUtc = TimeSpan.ParseExact(temp, "hhmmss", null);
                }

                temp = record.Element("daylight_savings").Attribute("data").Value;
                if (!string.IsNullOrEmpty(temp))
                {
                    ticker.DaylightSaving = bool.Parse(temp);
                }

                tickers.Add(ticker);
            }

            return tickers;
        }

        private static void PublishHistory(string symbol, DateTime start, DateTime end, Period period)
        {
            if (string.IsNullOrEmpty(symbol))
            {
                return;
            }

            if (start > end)
            {
                return;
            }

            List<History> history = new List<History>();

            using (WebClient web = new WebClient())
            {
                string data = web.DownloadString(string.Format(historyUrl, symbol, start, end, period));

                data = data.Replace("\r", "");

                string[] rows = data.Split('\n');

                //First row is headers so Ignore it
                for (int i = 1; i < rows.Length; i++)
                {
                    if (rows[i].Replace("\n", "").Trim() == "") continue;

                    string[] cols = rows[i].Split(',');

                    History hs = new History();
                    hs.Symbol = symbol;
                    hs.Date = DateTime.Parse(cols[0]);
                    hs.Open = decimal.Parse(cols[1]);
                    hs.High = decimal.Parse(cols[2]);
                    hs.Low = decimal.Parse(cols[3]);
                    hs.Close = decimal.Parse(cols[4]);
                    hs.Volume = uint.Parse(cols[5]);

                    history.Add(hs);
                }

                int size = connector.Publish<History, List<History>>(1, history);
                Console.WriteLine("Size: {0}", size);
            }
        }
    }
}